Rebuild glyph instance editing and canvas runtime#47
Merged
Conversation
End-to-end replacement of the old TextRunController. New layered architecture:
Layer 0 (pure, immutable geometry):
Cell = GlyphCell | LineBreak (tagged union, replaces flat GlyphRef + magic ".newline")
Positioner: harfbuzz-shaped no-shape positioner; will swap in shaping later
TextLayout: splitParagraphs → segmentRuns → position → assembleLayout, hit-test, pointAt
Caret: immutable cursor projection over a TextLayout
All built against the real MutatorSans font via shared testUtils.ts
Layer 1 (state):
TextBuffer: per-field signals (cells/cursor/anchor/originX), #update(patch) batching
TextInteraction: editing slot + suspended + hover (composite drill-through dropped)
TextRun: composes both, exposes layout/caret/selectionRects ComputedSignals,
threads goalX for vertical nav, wraps mutations to keep editing state coherent
TextRuns: per-glyph store with reactive active and serialize/deserialize
Wire-up:
Editor: textRuns + textRun getter; persistence effect tracks active run buffer
HiddenTextInput: rewired to editor.textRun.{insert,delete,move...}
Text tool, TextRunHover, TextRunEdit: minimal stubs to be refilled
Validation schema: PersistedTextRun now { buffer: TextBufferSnapshot } (Cell-shaped)
Renames + tightening:
GlyphRef → Cell, unicode → codepoint, glyphRefFromUnicode → cellFromCodepoint
GlyphView gains a bounds getter (delegates to font.getBbox)
Positioner is the single class; interface dropped (structural typing)
Deferred for follow-up:
Caret.nextLine/previousLine, TextRun vertical/word/line-edge nav
TextLayout.shapeHitTest
TextRunRenderer (canvas-side draw, indicator-pattern class)
TextRunHover + TextRunEdit real impls
Composite drill-through (own class when rebuilt)
Tests: 542 desktop + 112 validation passing, full typecheck clean.
Bundles four threads that share consumers (Editor.ts, tools/text/Text.ts) and cannot be split without breaking typecheck on intermediate commits: - Promote text/* out of tools/ into lib/text; finalize Cell + TextRun with stable cell ids carried through the persistence schema. - Replace startEditSession(glyphName, unicode?) with a GlyphHandle object on NativeBridge; ripple through every test caller. - Render text runs in the editor scene via rendering/Text.ts; rework Editor focused-glyph reactivity around GlyphAnchor + Positioner. - Renames: graphics ReglHandleContext → Gpu, tools text TypingBehaviour → TypingBehavior, tool class Text → TextTool.
Rename the core editing crate to shift-edit, move native bridge ownership from shift-node to shift-bridge, and introduce shift-wire as the DTO boundary shared by bridge adapters. Font loading moves into shift-backends, while shift-edit owns edit session state, glyph structure restoration, interpolation, and active edit mutation semantics. The bridge now uses typed errors and active edit state instead of the old edit-session/snapshot paths. This is a migration checkpoint: Rust workspace tests exclude the NAPI cdylib, while the native bridge is verified through the NAPI debug build. Renderer call sites are still being moved onto the new API in later commits. Verified with cargo test --workspace --exclude shift-bridge, cargo clippy --workspace --all-targets --exclude shift-bridge -- -D warnings, and pnpm --filter shift-bridge run build:debug.
Add @shift/bridge as the TypeScript package boundary for constructing the native bridge, and make @shift/types the generated DTO surface for NAPI bridge types.
Replace the old ts-rs generated type tree with bridge declaration generation, wire the package into pnpm/turbo, and expose the bridge through preload under the new Bridge naming. The package includes a CommonJS entry so Electron preload can require it at runtime.
This intentionally does not finish renderer model migration; it only establishes how TypeScript imports the native bridge and its DTOs.
Verified with pnpm --filter @shift/bridge typecheck and require('@shift/bridge') from apps/desktop.
- introduce Glyph/GlyphSource/Source edit boundaries - move reusable glyph geometry into @shift/glyph-state - replace node position updates with source positions and edit drafts - remove snapping and clean up select/pen editing flows - update bridge APIs, clipboard handling, tests, and docs
Rework the editor architecture around explicit source/preview glyph state, reactive render models, and tool-owned interaction state. - split editor state into focused domains for glyph/source context, camera/input, selection, hover, text editing, and glyph display - replace viewport/rendering manager paths with Camera, Renderer, render frames, canvas surfaces, and CanvasItem render boundaries - move selection, hover, hit, bounding box, marquee, and segment affordance logic out of loose renderer/types modules and into editor or tool-owned surfaces - introduce source-aware glyph state, sparse position patches, render models, keyed cache support, and outline/path invalidation so edit previews can update without rebuilding full geometry - update select and pen tools to use richer domain hit/query surfaces and tool-local drawing components - consolidate handle rendering around overlay/marker backends and keep marker upload ownership inside rendering infrastructure - add signal debugging, dependency naming, agent skill sync, jsdoc guidance, and focused tests for source geometry freshness, drafts, selection, camera, bounding boxes, and rendering primitives - update Rust bridge/edit-session paths for sparse position patching and source-aware glyph synchronization
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Verification